﻿using MCUPackage;
using MCUPackage.DesignEditor;
using MCUPackage.Utils;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;

namespace SxPackages.STC8.Models
{
	/// <summary>
	/// 串口设置基类
	/// </summary>
	[Serializable]
	class USARTOptionBase
	{
		protected STC8HUSOP20 mParent = null;

		/// <summary>
		/// 串口序号
		/// </summary>
		[Browsable(false)]
		[JsonIgnore]
		public int Id { get; protected set; }
		/// <summary>
		/// 使用的引脚名结合
		/// </summary>
		protected string[] mUsePins { get; set; }
		protected virtual void SetPins(string[] aPins)
		{

		}

		/// <summary>
		/// 切换引脚
		/// </summary>
		/// <param name="aNew"></param>
		/// <param name="aOld"></param>
		/// <returns>是否切换成功</returns>
		protected bool SwitchPins(string aNew, string aOld)
		{
			string[] newPins = TemplateHelper.GetPins(aNew);
			string[] oldPins = TemplateHelper.GetPins(aOld);

			if (this.Enable)
			{
				if (mParent.PinIsUsedTips(newPins))
				{
					return false;
				}
				// 清除占用的功能脚
				mParent.ResetPins(oldPins);
				SetPins(newPins);
			}

			mUsePins = newPins;
			return true;
		}

		private bool mEnable = false;
		[DisplayName("使能"),
		DefaultValue(false),
		JsonProperty(Order = 100),
		Description("是否使能本串口"),
		PropertyOrder(0)]
		public virtual bool Enable
		{
			get => mEnable;
			set
			{
				if (value != mEnable)
				{
					if (value)
					{
						if (TimeIsUsed(this.Timer))
						{
							GuiUtils.MsgBox($"定时器{(int)this.Timer}已经启用, 无法被用于本串口波特率发生器.");
							return;
						}
						if (mParent.PinIsUsedTips(mUsePins))
						{
							return;
						}
						if (BaudIsDiff(Timer, BaudRate))
						{
							return;
						}
						// 设置引脚用途
						SetPins(mUsePins);
					}
					else
					{
						// 清除占用的功能脚
						mParent.ResetPins(mUsePins);
					}

					mEnable = value;
				}
			}
		}

		private USARTMode mMode = USARTMode.可变波特率8位数据方式;
		[DisplayName("工作模式"),
		DefaultValue(USARTMode.可变波特率8位数据方式),
		Description("本串口的工作模式, 串口1与串口2可工作在同步移位与固定波特率9位数据方式")]
		public USARTMode Mode
		{
			get => mMode;
			set
			{
				if (value != mMode)
				{
					if (Id > 2)
					{
						if (value == USARTMode.同步移位方式 || value == USARTMode.固定波特率9位数据方式)
						{
							// 串口3, 4不支持以上两种方式
							return;
						}
					}
					if (value == USARTMode.同步移位方式 || value == USARTMode.可变波特率8位数据方式)
					{
						EnableMult = false;
					}
					mMode = value;
				}
			}
		}

		/// <summary>
		/// 判断指定的定时器是否被占用
		/// </summary>
		/// <param name="aTimer"></param>
		/// <returns></returns>
		private bool TimeIsUsed(UartTimer aTimer)
		{
			if (mParent.Tmrs == null)
			{
				return false;
			}
			var tmrs = mParent.mTmrs.All;
			foreach (var tmr in tmrs)
			{
				if ((int)aTimer == tmr.Id && tmr.Enable)
				{
					return true;
				}
			}

			return false;
		}

		private UartTimer mTimer = UartTimer.Timer2;
		[DisplayName("时钟源"),
		DefaultValue(UartTimer.Timer2),
		Description("本串口波特率发生器需要使用的时钟源")]
		public UartTimer Timer
		{
			get => mTimer;
			set
			{
				if (value != mTimer)
				{
					if (Enable)
					{
						if (value != UartTimer.Timer2 && (int)value != Id)
						{
							GuiUtils.MsgBox($"串口{Id}只能使用定时器{Id}与定时器2!");
							return;
						}
						if (TimeIsUsed(value))
						{
							GuiUtils.MsgBox($"定时器{(int)value}已经启用, 无法被用于本串口波特率发生器.");
							return;
						}
						if (BaudIsDiff(value, BaudRate))
						{
							// 确保定时器2波特率设置一致
							return;
						}
					}

					mTimer = value;
				}
			}
		}

		/// <summary>
		/// 对波特率进行检验
		/// </summary>
		/// <param name="aBaud"></param>
		/// <returns></returns>
		private bool BaudIsDiff(UartTimer aTmr, int aBaud)
		{
			if (aTmr != UartTimer.Timer2)
			{
				return false;
			}
			// 检查其他使用定时器2的波特率是否相同
			USARTOptionBase[] opts = mParent.mUarts.All;
			for (int i = 0; i < opts.Length; i++)
			{
				if (Id != opts[i].Id && opts[i].Enable && opts[i].Timer == UartTimer.Timer2)
				{
					if (aBaud != opts[i].BaudRate)
					{
						GuiUtils.MsgBox($"定时器2已经被串口{opts[i].Id}使用产生了{opts[i].BaudRate}波特率, 本串口如需使用定时器2请保持波特率一致!");
						return true;
					}
				}
			}

			return false;
		}

		private int mBaudRate = 9600;
		[DisplayName("波特率"),
		DefaultValue(9600),
		Description("串口波特率设置, 1200~115200"),
		TypeConverter(typeof(IntCollectionConvertor)),
		IntCollection(new int[] { 1200, 2400, 4800, 9600, 14400, 19200, 28800, 38400, 57600, 115200 })]
		public int BaudRate
		{
			get => mBaudRate;
			set
			{
				if (value != mBaudRate)
				{
					if (Enable)
					{
						if (BaudIsDiff(Timer, value))
						{
							return;
						}
					}
					mBaudRate = value;
				}
			}
		}

		[DisplayName("接收使能"),
		DefaultValue(true),
		Description("是否使能串口的接收功能")]
		public bool EnableRcv { get; set; } = true;

		private bool mEnableMult = false;
		[DisplayName("使能多机通信"),
		DefaultValue(false),
		Description("是否使能串口的多机通信功能, 工作在模式为波特率9位时可以使能")]
		public bool EnableMult
		{
			get => mEnableMult;
			set
			{
				if (value != mEnableMult)
				{
					if (value && (Mode == USARTMode.同步移位方式 || Mode == USARTMode.可变波特率8位数据方式))
					{
						return;
					}
				}

				mEnableMult = value;
			}
		}

		[DisplayName("中断使能"),
		DefaultValue(true),
		Description("是否使能串口中断")]
		public bool EnableTI { get; set; } = true;

		[DisplayName("中断优先级"),
		Description("中断优先级等级设置"),
		DefaultValue(PriorityTypes.最低级)]
		public PriorityTypes Priority { get; set; } = PriorityTypes.最低级;

		public USARTOptionBase(STC8HUSOP20 aParent)
		{
			this.mParent = aParent;
		}

		public override String ToString()
		{
			return string.Empty;
		}

		/// <summary>
		/// 初始化模板
		/// </summary>
		private const string TEMPLATE =
@"	attr.UART_Mode      = {0};	//模式, UART_ShiftRight,UART_8bit_BRTx,UART_9bit,UART_9bit_BRTx
	attr.UART_BRT_Use   = BRT_Timer{1};			//选择波特率发生器 (注意: 串口2固定使用BRT_Timer2)
	attr.UART_BaudRate  = {2}ul;			//波特率, 一般 110 ~ 115200
	attr.UART_RxEnable  = {3};				//接收允许,   ENABLE或DISABLE
	attr.BaudRateDouble = {4};			//波特率加倍, ENABLE或DISABLE
	UART_Configuration(UART{5}, &attr);		//初始化串口1 UART1,UART2,UART3,UART4
	NVIC_UART{5}_Init({6}, {7});		//中断使能, ENABLE/DISABLE; 优先级(低到高) Priority_0,Priority_1,Priority_2,Priority_3
	UART{5}_SW(UART{5}_SW{8});";

		public string[] Generate(Dictionary<string, List<string>> aLst)
		{
			if (!this.Enable)
			{
				return null;
			}

			StringBuilder funcSb = new StringBuilder();
			string pins = string.Empty;
			foreach (var pin in mUsePins)
			{
				var opt = mParent.GetPinOption(pin);
				if (opt != null)
				{
					opt.ToSTC8Dictionary(aLst);
					pins += "_";
					pins += pin.Replace(".", "");
				}
			}

			funcSb.AppendFormat(TEMPLATE, this.Mode.ToDescription(), (int)this.Timer, this.BaudRate,
								this.EnableRcv.ToEnable(), false.ToEnable(), this.Id,
								this.EnableTI.ToEnable(), this.Priority.ToDescription(), pins);
			funcSb.AppendLine();

			return new string[] { funcSb.ToString() };
		}
	}
}
